package de.fzi.kasma.learner.function.prediction;

import de.fzi.kasma.learner.data.Data;
import de.fzi.kasma.learner.data.Dataset;
import de.fzi.kasma.learner.data.Label;
import de.fzi.kasma.learner.function.kernel.HypothesisKernel;
import de.fzi.kasma.learner.function.kernel.KernelMatrix;
import de.fzi.kasma.learner.svm.libsvm.svm;
import de.fzi.kasma.learner.svm.libsvm.svm_model;
import de.fzi.kasma.learner.svm.libsvm.svm_node;
import de.fzi.kasma.learner.svm.libsvm.svm_parameter;
import de.fzi.kasma.learner.svm.libsvm.svm_problem;

public class SVMPredictionFunction extends PredictionFunction{
	
	svm_model model;
	HypothesisKernel kernel;
	Dataset dataset;
	double complexity;

	public double getComplexity() {
		return complexity;
	}

	public SVMPredictionFunction(Dataset d,HypothesisKernel k) throws Exception
	{
		this.kernel = k;
		this.dataset = d;
		this.model = getModel(k, d);
		this.complexity = k.getComplexity();

	}

	private svm_model getModel(HypothesisKernel k, Dataset d) {
		
		
		Data[] orderedData = null;
		try {
			orderedData = dataset.getAllData();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        KernelMatrix km = k.calculateKernelMatrix(dataset);
		   svm_problem problem = getProblem(km);
		   svm_parameter parameter = getParameters();
        svm_model model = svm.svm_train(problem, parameter);
	 
		return model;
	}

	private svm_parameter getParameters() {
		svm_parameter params = new svm_parameter();

		params.svm_type = 0;
		params.kernel_type = 4;

		// default values

		params.degree = 3;
		params.gamma = 0;	// 1/num_features
		params.coef0 = 0;
		params.nu = 0.5;
		params.cache_size = 100;
		params.C = 1;
		params.eps = 1e-3;
		params.p = 0.1;
		params.shrinking = 1;
		params.probability = 0;
		params.nr_weight = 0;
		params.weight_label = new int[0];
		params.weight = new double[0];

		return params;
		
	}

	private svm_problem getProblem(KernelMatrix km) {

		/** the svm problem just reads the values from the kernel matrix 
		 *   if the kernel matrix has the following form: <label>  i   K(xi,x1) ...  K(xi,xL)
		 *   	15    1    4    6     1
		 *   	45    2    6    18    0 
		 *   	25    3    1    0     1
		 *   the first column is for the labels, the second is the index of the instance,
		 *   the rest of each line are the ordered kernels
		 */
				svm_problem problem = new svm_problem();
				double [][] matrixvalues = km.matrix;
				int examplesNumber = matrixvalues.length;
				problem.l = examplesNumber;
				problem.y = new double[examplesNumber];
				problem.x = new svm_node[examplesNumber][];

				
				for (int i = 0; i < matrixvalues.length; i++) {
					 problem.y[i] = matrixvalues[i][0];
					 svm_node[] m = new svm_node[matrixvalues.length+1];
					for (int j = 1; j < matrixvalues.length+2; j++) {
						svm_node n = new svm_node();
		    			n.index = j-1;
		    			n.value = matrixvalues[i][j];
		    			m[j-1] = n;
					}
					problem.x[i] =  m;
				}
				
					return problem;
	}

	@Override
	public Label getPrediction(Data x) {
	
		
		Data[] orderedData = null;
		try {
			orderedData = dataset.getAllData();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		KernelMatrix mk = kernel.calculateMatrix(dataset, x);
		int l = mk.matrix[0].length;
		svm_node[] xnodes = new svm_node[l];
		for (int i = 0; i<l; i++){
			svm_node n = new svm_node();
			n.index = i;
			n.value = mk.matrix[0][i+1];
			xnodes[i] = n;
		}
	    double prediction = svm.svm_predict(model, xnodes);
	    Label label = new Label();
	    label.setValue(prediction);
	    return label;
	}

}
